<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }


        #Buts {
            position: absolute;
            top: 0;
        }
    </style>
</head>

<body>

    <canvas id="canvas">

    </canvas>
    <div id="Buts">
        <button id="former">正</button>
        <button id="top">顶</button>
        <button id="left">侧</button>
    </div>
</body>

<script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    uniform mat4 u_PvM4;
    uniform mat4 u_ModelM4;
    void main(){
        gl_Position = u_PvM4 * u_ModelM4 * a_Position;
    }
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
    precision mediump float;
    uniform vec4 u_Color;
    void main(){
      gl_FragColor = u_Color;
    }
</script>
<script type="module">
    import { Matrix4, Vector2, Vector3, Color, OrthographicCamera, Quaternion } from '../js/three.module.js';
    import Poly from '../js/Poly3.js';
    import { initShaders } from '../js/Utils.js';
    import lib from '../js/ThreeLib.js';


    //#region gl
    const canvas = document.getElementById("canvas");
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight - 4;

    const gl = canvas.getContext("webgl");
    //开始背景遮挡
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    gl.enable(gl.DEPTH_TEST);

    initShaders(gl,
        document.querySelector("#vertexShader").innerText,
        document.querySelector("#fragmentShader").innerText);
    lib.clearCanvas(gl, new Color("rgba(0,0,0,1)"), 1);
    //#endregion

    //#region 创建相机
    const halfH = 2;
    const ratio = canvas.width / canvas.height;
    const halfW = halfH * ratio;

    const [left, right, top, bottom, near, far] = [
        -halfW, halfW,
        halfH, -halfH,
        -10, 10
    ];
    const camera = new OrthographicCamera(left, right, top, bottom, near, far);
    //#endregion

    const eye = new Vector3(0, 0, 3);//相机位置
    const lookAt = new Vector3(0, 0, 0);//看向的位置
    const zoomScale = 0.05;//缩放系数
    const pi2 = Math.PI * 2;
    const length = 99;//坐标长度

    const pvM4 = getPvM4(eye, lookAt);

    const mouseButtons = new Map([
        [0, 'left'],
        [2, 'right'],
    ]);
    //鼠标位移的偏转量
    const [dragCur, dragLast] = [
        new Vector2(),
        new Vector2()
    ];
    //用于旋转的四元数
    const quaternion = new Quaternion();


    let state = 'none';

    const polyArr = [];


    let v3 = new Vector3(1, 2, 3);
    let m4 = new Matrix4(
        1, 0, 0, 0,
        0, 1, 0, 0,
        0, 0, 1, 0,
        2, 3, 4, 1
    );
    // console.log(v3.applyMatrix4(m4));

    //Main
    (function main() {

        var m4 = new Matrix4(
            1, 0, 0, 0,
            0, 1, 0, 0,
            0, 0, 1, 0,
            0, 0, 0, 1
        );



        let poly1 = create(
            [1, 0, 0, 1],
            new Matrix4().setPosition(-0.3, 0, -2)
        );
        let poly2 = create(
            [0, 1, 0, 1],
            new Matrix4().setPosition(-0.1, 0, -3)
        );
        let poly3 = create(
            [0, 0, 1, 1],
            new Matrix4().setPosition(0.1, 0, -4)
        );
        let poly4 = create(
            [1, 1, 1, 1],
            new Matrix4().setPosition(0.3, 0, -5)
        );


        let poly5 = new Poly({
            gl: gl,
            arr: [
                0, -length, 0,
                0, length, 0,
                length, 0, 0,
                -length, 0, 0,
                0, 0, length,
                0, 0, -length
            ],
            list: [
                { name: 'a_Position', size: 3, beginIndex: 0 }
            ],
            uniforms: {
                'u_Color': {
                    type: 'uniform4fv',
                    value: [1, 1, 1, 1]
                },
                'u_PvM4': {
                    type: 'uniformMatrix4fv',
                    value: pvM4.elements
                },
                'u_ModelM4': {
                    type: 'uniformMatrix4fv',
                    value: new Matrix4().elements
                },
            }
        });

        polyArr.push(
            [['TRIANGLES'], poly1],
            [['TRIANGLES'], poly2],
            [['TRIANGLES'], poly3],
            [['TRIANGLES'], poly4],
            [['LINES'], poly5],
        )

        rend();
    })();




    canvas.addEventListener('contextmenu', (event) => {
        event.preventDefault();
    });
    canvas.addEventListener('pointerdown', (event) => {
        dragCur.set(event.clientX, event.clientY);
        dragLast.copy(dragCur);
        state = mouseButtons.get(event.button);
    });
    canvas.addEventListener('pointermove', ({ clientX, clientY }) => {
        dragCur.set(clientX, clientY)
        switch (state) {
            case 'right':
                cameraPosition(dragCur.clone().sub(dragLast))
                break;
            case 'left':
                cameraRotation(dragCur.clone().sub(dragLast));
                break;
        }
        dragLast.copy(dragCur);

    });
    canvas.addEventListener('pointerup', (event) => {
        state = 'none';
        // console.log(camera.rotation)
    });
    canvas.addEventListener('wheel', function ({ deltaY }) {
        cameraZoom(deltaY);
    })

    //#region 旋转
    function cameraRotation(moveDiff) {
        const { right, left, top, bottom, matrix, position } = camera;
        const { clientWidth, clientHeight } = canvas;

        //相机的宽高
        const cameraW = right - left;
        const cameraH = top - bottom;

        //计算视图偏移量
        const ratioX = moveDiff.x / clientWidth;
        const ratioY = -moveDiff.y / clientHeight;

        const ratioXBaseHeight = moveDiff.x / clientHeight;
        //位移量
        const ratioLen = new Vector2(ratioXBaseHeight, ratioY).length();
        //旋转量
        const angle = ratioLen * pi2;

        //在相机世界中的位移距离
        const distanceLeft = ratioX * cameraW;
        const distanceUp = ratioY * cameraH;

        // 相机本地坐标系的x,y轴
        const mx = new Vector3().setFromMatrixColumn(camera.matrix, 0);
        const my = new Vector3().setFromMatrixColumn(camera.matrix, 1);

        // 将鼠标在相机世界的x,y轴向的位移量转换为世界坐标位
        const vx = mx.clone().multiplyScalar(distanceLeft);
        const vy = my.clone().multiplyScalar(distanceUp);

        //鼠标在世界坐标系中的位移方向-x轴
        const moveDir = vx.clone().add(vy).normalize();

        //目标点到视点的单位向量-z轴
        const eyeDir = camera.position.clone().sub(lookAt).normalize();


        //基于位移方向和视线获取旋转轴-上方向y轴
        const axis = moveDir.clone().cross(eyeDir);


        //基于旋转轴和旋转量建立四元数
        quaternion.setFromAxisAngle(axis, angle);

        console.log(axis)

        updateRotation(quaternion);

    }

    function updateRotation(quaternion) {
        // console.log(quaternion)
        const rotateOffset = camera.position.clone()
            .sub(lookAt)
            .applyQuaternion(quaternion)

        camera.position.copy(
            lookAt.clone().add(rotateOffset)
        )

        camera.up.applyQuaternion(quaternion)
        camera.lookAt(lookAt);
        camera.updateMatrixWorld(true)
        pvM4.multiplyMatrices(
            camera.projectionMatrix,
            camera.matrixWorldInverse,
        )

        rend();


    }
    //#endregion 

    //#region 移动
    function cameraPosition(moveDiff) {
        const { right, left, top, bottom, matrix, position } = camera;
        const { clientWidth, clientHeight } = canvas;
        //相机的宽
        const cameraW = right - left;
        //相机的高
        const cameraH = top - bottom;

        //计算视图偏移量
        const ratioX = moveDiff.x / clientWidth;
        const ratioY = moveDiff.y / clientHeight;

        //将视图偏移量映射到相机偏移量
        const distanceLeft = ratioX * cameraW;
        const distanceUp = ratioY * cameraH;

        //拿到相机本地坐标系的X轴
        const mx = new Vector3().setFromMatrixColumn(matrix, 0);
        const my = new Vector3().setFromMatrixColumn(matrix, 1);

        //计算视图偏移量
        const vx = mx.multiplyScalar(-distanceLeft);
        const vy = my.multiplyScalar(distanceUp);

        updatePosition(vx.add(vy));
    }

    function updatePosition(vec3) {
        camera.position.add(vec3);
        camera.lookAt(lookAt.add(vec3));
        camera.updateMatrixWorld(true);
        pvM4.multiplyMatrices(
            camera.projectionMatrix,
            camera.matrixWorldInverse
        );
        rend();
    }
    //#endregion

    //#region 缩放
    function cameraZoom(zoomDiff) {
        const { right, left, top, bottom, matrix, position, up } = camera;

        const cX = (right - left) / 2;
        const cY = (top - bottom) / 2;

        if (zoomDiff < 0) {
            updateZoom(1 + zoomScale);
        } else {
            updateZoom(1 - zoomScale);
        }
    }

    function updateZoom(scale) {
        camera.zoom *= scale;
        camera.updateProjectionMatrix();

        pvM4.multiplyMatrices(
            camera.projectionMatrix,
            camera.matrixWorldInverse
        );
        rend();
    }
    //#endregion


    function getPvM4(eye, lookAt) {
        camera.position.copy(eye);
        camera.lookAt(lookAt);
        return new Matrix4().multiplyMatrices(
            camera.projectionMatrix,
            camera.matrixWorldInverse
        );
    }

    //创建Poly
    function create(color, modelM4) {
        // poly.draw(["TRIANGLES", "POINTS"]);
        return new Poly({
            gl: gl,
            arr: [
                0, 0.3, 0,
                0.3, -0.3, 0,
                -0.3, -0.3, 0
            ],
            list: [
                { name: 'a_Position', size: 3, beginIndex: 0 }
            ],
            uniforms: {
                'u_Color': {
                    type: 'uniform4fv',
                    value: color
                },
                'u_PvM4': {
                    type: 'uniformMatrix4fv',
                    value: pvM4.elements
                },
                'u_ModelM4': {
                    type: 'uniformMatrix4fv',
                    value: modelM4.elements
                },
            }
        });
    }

    //渲染
    function rend() {
        lib.clearCanvas(gl, new Color("rgba(0,0,0,1)"), 1);
        polyArr.forEach(u => {
            u[1].init();
            u[1].draw(u[0]);
        });
    }

    //#region button 有问题
    document.getElementById('former').addEventListener('click', function () {
        let c1 = eye.distanceTo(lookAt)
        eye.set(lookAt.x, lookAt.y, (lookAt.z + c1));

        camera.position.copy(eye);
        camera.lookAt(lookAt);
        camera.rotation.set(0, 0, 0);

        camera.updateMatrixWorld(true);
        pvM4.multiplyMatrices(
            camera.projectionMatrix,
            camera.matrixWorldInverse
        );
        rend();
    })
    //#region button 有问题
    // document.getElementById('top').addEventListener('click', function () {
    //     let c1 = eye.distanceTo(lookAt)
    //     eye.set(lookAt.x, lookAt.y, 0);

    //     camera.position.copy(eye);
    //     camera.lookAt(lookAt);
    //     camera.rotation.set(-80 * Math.PI / 180, 0, 0);

    //     camera.updateMatrixWorld(true);
    //     pvM4.multiplyMatrices(
    //         camera.projectionMatrix,
    //         camera.matrixWorldInverse
    //     );
    //     rend();

    //     console.log(eye, lookAt)
    // })

    //#endregion

</script>

</html>